package com.android.lovely.manager

import android.os.Parcelable
import androidx.core.net.toUri
import com.android.lovely.R
import com.android.lovely.api.service.upload
import com.android.lovely.api.service.userService
import com.android.lovely.const.UpLoadStep
import com.android.lovely.framework.UIController.showToast
import com.android.lovely.room.role.CacheRoleServer
import com.android.lovely.room.role.CreateRole
import com.android.lovely.room.role.CreateRoleDataBase
import com.kotlin.extensions.bus.FlowBus
import com.kotlin.extensions.bus.post
import com.kotlin.extensions.coroutine.CoroutineExt.doOnIO
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.withContext
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
import java.io.File
import java.util.concurrent.atomic.AtomicInteger

// 上传策略接口
interface FileUploadStrategy {
    suspend fun executeUpload(file: File): String
}

// 默认上传策略实现
class DefaultFileUploadStrategy : FileUploadStrategy {
    override suspend fun executeUpload(file: File): String {
        return file.toUri().upload()
    }
}

// 上传进度观察者
interface UploadProgressListener {
    fun onProgressChanged(progress: Int)
}

// 上传管理器
class FileUploadManager(private val strategy: FileUploadStrategy) {
    private val listeners = mutableListOf<UploadProgressListener>()
    
    fun addListener(listener: UploadProgressListener) {
        listeners.add(listener)
    }
    
    fun removeListener(listener: UploadProgressListener) {
        listeners.remove(listener)
    }
    
    private fun notifyProgress(progress: Int) {
        listeners.forEach { it.onProgressChanged(progress) }
    }
    
    suspend fun uploadFile(file: File): String {
        val result = strategy.executeUpload(file)
        notifyProgress(1)
        return result
    }
}

// API请求工厂
object BotRequestFactory {
    fun createRequest(bot: CreateRole, id: Int? = null): Map<String, Any?> {
        return mapOf(
            "id" to id,
            "name" to bot.nickName,
            "introduction" to bot.introduction,
            "description" to bot.description,
            "nsfw" to if (bot.nsfw) 1 else 0,
            "first_message" to bot.firstMessage,
            "avatar" to bot.avatar,
            "gender" to bot.gender,
            "privacy" to if (bot.public) 1 else 2,
            "chat_example" to bot.chatExample,
            "scenario" to bot.scenario,
            "category" to bot.category,
            "search_tag" to bot.keywords.joinToString(","),
            "card_list" to bot.cards,
        )
    }
}

// Bot仓库
interface BotDataRepository {
    suspend fun createBot(request: Map<String, Any?>)
    suspend fun updateBot(id: Int, request: Map<String, Any?>)
    suspend fun deleteBot(id: Int)
}

class DefaultBotDataRepository : BotDataRepository {
    override suspend fun createBot(request: Map<String, Any?>) {
        userService.createBot(request)
    }
    
    override suspend fun updateBot(id: Int, request: Map<String, Any?>) {
        userService.updateBot(request)
    }
    
    override suspend fun deleteBot(id: Int) {
        CreateRoleDataBase.dao.delete(id)
        CacheRoleServer.remove(id)
    }
}

@Parcelize
data class UpLoadRoleManager (private val newBot: CreateRole) : Parcelable, UploadProgressListener {
    
    private val uploadManager = FileUploadManager(DefaultFileUploadStrategy())
    private val botRepository: BotDataRepository = DefaultBotDataRepository()
    
    init {
        uploadManager.addListener(this)
    }

    fun remove() {
        uploadManager.removeListener(this)
    }
    
    override fun onProgressChanged(progress: Int) {
        FlowBus.post(UpLoadStep(progress))
    }
    
    override fun describeContents(): Int = 0
    
    suspend fun executeCreation(): Boolean {
        return doOnIO {
            runCatching {
                uploadAvatar()
                if (newBot.avatar.isEmpty() || newBot.avatar.startsWith("http").not()) {
                    showToast(R.string.avatar_failed)
                    return@runCatching false
                }
                uploadPhotos()
                val failCount = newBot.cards.count { it.url.isEmpty() }
                if (failCount > 0) {
                    showToast(R.string.upload_photo_fail)
                    return@runCatching false
                }
                createBot()
                return@runCatching true
            }.onFailure {
                it.printStackTrace()
            }.getOrDefault(false)
        }
    }
    
    private suspend fun createBot() {
        val request = BotRequestFactory.createRequest(newBot, newBot.createId.takeIf { it > -1 })
        if (newBot.createId > -1) {
            botRepository.updateBot(newBot.createId, request)
        } else {
            botRepository.createBot(request)
        }
        botRepository.deleteBot(newBot.id)
    }
    
    private suspend fun uploadPhotos() = withContext(Dispatchers.IO) {
        val uploadedCount = AtomicInteger(0)
        val alreadyUploaded = newBot.cards.count { it.url.isNotEmpty() }
        FlowBus.post(UpLoadStep(alreadyUploaded))
        uploadedCount.set(newBot.cards.count { it.url.isNotEmpty() })

        newBot.cards
            .asSequence()
            .filterNot { it.url.isNotEmpty() }
            .map { card ->
                async {
                    runCatching {
                        card.url = uploadManager.uploadFile(File(card.localePath))
                    }
                }
            }.toList()
            .awaitAll()
    }
    
    private suspend fun uploadAvatar() {
        if (newBot.avatar.isNotEmpty() && !newBot.avatar.startsWith("http")) {
            runCatching {
                FlowBus.post(UpLoadStep(-1))
                newBot.avatar = uploadManager.uploadFile(File(newBot.avatar))
            }
        }
    }
}